//
// Created by xuyan on 2023/2/17.
//


#include "imagemedia.h"

ImageMedia::ImageMedia() {

}

ImageMedia::~ImageMedia() {

}

AVFrame* ImageMedia::decode(const char *file_path) {
    int ret;
    AVCodecContext *codec_ctx = nullptr;
    AVFrame *frame = nullptr;

    AVFormatContext *imageFormatContext = avformat_alloc_context();
    if (avformat_open_input(&imageFormatContext, file_path, nullptr, nullptr) < 0) {
        LOGE("图片解码文件打开失败！");
        avformat_free_context(imageFormatContext);
        return NULL;
    }
    if (avformat_find_stream_info(imageFormatContext, nullptr) < 0) {
        LOGE("图片解码没有找到数据流信息！");
        avformat_free_context(imageFormatContext);
        return NULL;
    }

    //打印信息
    av_dump_format(imageFormatContext, 0, file_path, 0);

    //获取视频流
    int img_index = av_find_best_stream(imageFormatContext, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr,
                                        0);
    if (img_index < 0) {
        LOGE("图片解码没有找到帧数据！");
        avformat_free_context(imageFormatContext);
        return NULL;
    }

    //-----------处理视频部分---------------------
     const AVCodec *codec = avcodec_find_decoder(imageFormatContext->streams[img_index]->codecpar->codec_id);
        if (!codec) {
            LOGE("图片解码没有找到相应的解码器！");
            avformat_free_context(imageFormatContext);
            return NULL;
        }


    // 初始化AVCodecContext
    codec_ctx = avcodec_alloc_context3(codec);
    if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {
        LOGE("图片解码打开解码器失败！");
        avformat_free_context(imageFormatContext);
        avcodec_close(codec_ctx);
        av_free(codec_ctx);
        return NULL;
    }

    //初始化packet
    AVPacket *packet = av_packet_alloc();
    if (!packet){
        avformat_free_context(imageFormatContext);
        av_packet_free(&packet);
        av_free(packet);
        avcodec_close(codec_ctx);
        av_free(codec_ctx);
    }

    // 初始化AVFrame
    frame = av_frame_alloc();
    if (!frame) {
        LOGE("图片解码申请avFrame内存失败");
        avformat_free_context(imageFormatContext);
        av_packet_free(&packet);
        av_free(packet);
        av_frame_free(&frame);
        av_free(frame);
        avcodec_close(codec_ctx);
        av_free(codec_ctx);
        return NULL;
    }
    // 读取数据包
    while (av_read_frame(imageFormatContext, packet) >= 0) {
        // 解码
       ret = avcodec_send_packet(codec_ctx,packet);

        if (ret < 0) {
            LOGE("avcodec_send_packet -> failure");
            continue;
        }

        ret = avcodec_receive_frame(codec_ctx,frame);

        if(ret < 0){
            LOGE("avcodec_receive_frame -> failure");
            break;
        }

        // 处理解码后的帧
        if (!frame) {
            LOGE("图片解码后数据为null");
            avformat_free_context(imageFormatContext);
            av_packet_free(&packet);
            av_free(packet);
            avcodec_close(codec_ctx);
            av_free(codec_ctx);
            return NULL;
        }
    }
    AVFrame *avframe = convertImgYUV(codec_ctx, frame);
    if (!avframe) {
        LOGE("图片解码后数据提取失败");
        avformat_free_context(imageFormatContext);
        av_packet_free(&packet);
        av_free(packet);
        av_frame_free(&frame);
        av_free(frame);
        avcodec_close(codec_ctx);
        av_free(codec_ctx);
        return NULL;
    }
    // 释放资源
    avformat_free_context(imageFormatContext);
    av_packet_free(&packet);
    av_free(packet);
    avcodec_close(codec_ctx);
    av_free(codec_ctx);
    return avframe;
}

AVFrame* ImageMedia::convertImgYUV(const AVCodecContext *codec_ctx, AVFrame *imgFrame) {
    AVFrame *yuv420p_avFrame = NULL;
    if (imgFrame->format == AV_PIX_FMT_YUV420P) {
        return imgFrame;
    } else {
        yuv420p_avFrame = av_frame_alloc();
        int yuv420pNum = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, codec_ctx->width,
                                                  codec_ctx->height, 1);
        uint8_t *yuv420p_buffer = (uint8_t *) malloc(yuv420pNum * sizeof(uint8_t));

        av_image_fill_arrays(
                yuv420p_avFrame->data,
                yuv420p_avFrame->linesize,
                yuv420p_buffer,
                AV_PIX_FMT_YUV420P,
                codec_ctx->width,
                codec_ctx->height,
                1);

        yuv420p_avFrame->width = codec_ctx->width;
        yuv420p_avFrame->height = codec_ctx->height;
        yuv420p_avFrame->format = AV_PIX_FMT_YUV420P;
        //不是YUV420p
        SwsContext *sws_ctx = sws_getContext(
                codec_ctx->width,
                codec_ctx->height,
                codec_ctx->pix_fmt,
                codec_ctx->width,
                codec_ctx->height,
                AV_PIX_FMT_YUV420P,
                SWS_BICUBIC, nullptr, nullptr, nullptr);

        if (!sws_ctx) {
            return NULL;
        }

        sws_scale(
                sws_ctx,
                imgFrame->data,
                imgFrame->linesize,
                0,
                imgFrame->height,
                yuv420p_avFrame->data,
                yuv420p_avFrame->linesize);


        sws_freeContext(sws_ctx);
        av_frame_free(&imgFrame);
        av_free(imgFrame);
        av_free(yuv420p_buffer);
        imgFrame = nullptr;
    }
    return yuv420p_avFrame;
}


//    jint src_y_size = width * height;
//    jint src_u_size = (width >> 1) * (height >> 1);
//
//    uint8_t *src_i420_y_data = yuv420p_buffer;
//    uint8_t *src_i420_u_data = yuv420p_buffer + src_y_size;
//    uint8_t *src_i420_v_data = yuv420p_buffer + src_y_size + src_u_size;

//    switch (imgFrame->format) {
//        case AV_PIX_FMT_YUV420P: {
//            av_image_fill_arrays(imgFrame->data, imgFrame->linesize, yuv420p_buffer,
//                                 AV_PIX_FMT_YUV420P, width, height, 1);
//            break;
//        }
//        case AV_PIX_FMT_YUV422P: {
//            int yuv422pNum = av_image_get_buffer_size(AV_PIX_FMT_YUV422P, imgFrame->width,
//                                                      imgFrame->height, 1);
//            uint8_t *yuv422_buffer = (uint8_t *) malloc(yuv422pNum);
//            av_image_fill_arrays(imgFrame->data, imgFrame->linesize, yuv422_buffer,
//                                 AV_PIX_FMT_YUV422P, width, height, 1);
//
//            uint8_t *src_i422_y_data = yuv422_buffer;
//            uint8_t *src_i422_u_data = yuv422_buffer + src_y_size;
//            uint8_t *src_i422_v_data = yuv422_buffer + src_y_size + src_u_size;
//
//            libyuv::I422ToI420(src_i422_y_data, width,
//                               src_i422_u_data, width >> 1,
//                               src_i422_v_data, width >> 1,
//                               src_i420_y_data, width,
//                               src_i420_u_data, width >> 1,
//                               src_i420_v_data, width >> 1,
//                               width, height);
//            free(yuv422_buffer);
//            break;
//        }
//        case AV_PIX_FMT_YUV444P: {
//            int yuv444pNum = av_image_get_buffer_size(AV_PIX_FMT_YUV444P, width, height, 1);
//            uint8_t *yuv444_buffer = (uint8_t *) malloc(yuv444pNum);
//            av_image_fill_arrays(imgFrame->data, imgFrame->linesize, yuv444_buffer,
//                                 AV_PIX_FMT_YUV444P, width, height, 1);
//
//            uint8_t *src_i444_y_data = yuv444_buffer;
//            uint8_t *src_i444_u_data = yuv444_buffer + src_y_size;
//            uint8_t *src_i444_v_data = yuv444_buffer + src_y_size + src_u_size;
//
//            libyuv::I444ToI420(src_i444_y_data, width,
//                               src_i444_u_data, width >> 1,
//                               src_i444_v_data, width >> 1,
//                               src_i420_y_data, width,
//                               src_i420_u_data, width >> 1,
//                               src_i420_v_data, width >> 1,
//                               width, height);
//            free(yuv444_buffer);
//            break;
//        }
//        case AV_PIX_FMT_ARGB: {
//            int yuvARGBpNum = av_image_get_buffer_size(AV_PIX_FMT_ARGB, width, height, 1);
//            uint8_t *yuvARGB_buffer = (uint8_t *) malloc(yuvARGBpNum);
//            av_image_fill_arrays(imgFrame->data, imgFrame->linesize, yuvARGB_buffer,
//                                 AV_PIX_FMT_ARGB, width, height, 1);
//
//            libyuv::ARGBToI420(yuvARGB_buffer, width * 4,
//                               src_i420_y_data, width,
//                               src_i420_u_data, width >> 1,
//                               src_i420_v_data, width >> 1,
//                               width, height);
//            free(yuvARGB_buffer);
//            break;
//        }
//        case AV_PIX_FMT_RGBA:{
//            int yuvRGBApNum = av_image_get_buffer_size(AV_PIX_FMT_RGBA, width, height, 1);
//            uint8_t *yuvRGBA_buffer = (uint8_t *) malloc(yuvRGBApNum);
//            av_image_fill_arrays(imgFrame->data, imgFrame->linesize, yuvRGBA_buffer,
//                                 AV_PIX_FMT_RGBA, width, height, 1);
//
//            libyuv::RGBAToI420(yuvRGBA_buffer,width * 4,
//                               src_i420_y_data, width,
//                               src_i420_u_data, width >> 1,
//                               src_i420_v_data, width >> 1,
//                               width, height);
//            free(yuvRGBA_buffer);
//            break;
//        }
//    }

